use core::{
    convert::{TryFrom, TryInto},
    iter::{Enumerate, FilterMap},
    marker::PhantomData,
};

use super::Bit;

use crate::{Bits, BitsOps, IntoBits};

/// # Bits 迭代器
///
/// ~~⚠️ 性能较差，比手动掩码移位循环慢三分之一左右。~~
/// 目前使用迭代器的速度要比手动编码快 99%，很戏剧化。
pub struct BitsIter<V: IntoBits> {
    pub(crate) value: V,
    pub(crate) low: u32,
    pub(crate) upper: u32,
}

impl<V: IntoBits> Iterator for BitsIter<V> {
    type Item = Bit<V>;

    fn next(&mut self) -> Option<Self::Item> {
        let ret = if self.low <= self.upper {
            Some(Bit {
                value: self.value.bits(self.low).read(),
            })
        } else {
            None
        };
        self.low += 1;
        ret
    }
}

/// En::into::<u32>() 用于指示 T 中第 nth 个 bit，而不是掩码 1 << nth 。
pub struct BitMap<T, Pos = u32>
where
    Bits<T>: BitsOps<T>,
    Pos: Into<u32> + TryFrom<u32>,
    T: Sized + IntoBits<Output = Bits<T>>,
{
    raw: T,
    _phantom: PhantomData<Pos>,
}

impl<T, Pos> BitMap<T, Pos>
where
    Bits<T>: BitsOps<T>,
    Pos: Into<u32> + TryFrom<u32>,
    T: Sized + IntoBits<Output = Bits<T>>,
{
    pub fn new(raw_bitmap: T) -> Self {
        Self {
            raw: raw_bitmap,
            _phantom: PhantomData,
        }
    }
    /// 用于快速的确定 bitmap 中某一个 bit 是否置位
    pub fn is_setted(&self, pos: Pos) -> bool {
        let pos: u32 = pos.into();
        self.raw.bits(pos).is_set()
    }
    pub fn set(&mut self, pos: Pos) {
        self.raw = self.raw.bits(pos.into()).set()
    }
    pub fn raw(&self) -> T {
        self.raw
    }
    #[inline(always)]
    pub fn any_undefined(&self) -> bool {
        for (pos, bit) in self.raw.bits(..).into_iter().enumerate() {
            if Pos::try_from(pos as u32).is_err() && bit.is_set() {
                return false;
            }
        }
        true
    }
}

pub struct BitMapIter<T, Pos>
where
    Bits<T>: BitsOps<T>,
    Pos: Into<u32> + TryFrom<u32>,
    T: Sized + IntoBits<Output = Bits<T>>,
{
    raw_iter: FilterMap<Enumerate<BitsIter<T>>, fn((usize, Bit<T>)) -> Option<Pos>>,
}
impl<T, Pos> Iterator for BitMapIter<T, Pos>
where
    Bits<T>: BitsOps<T>,
    Pos: Into<u32> + TryFrom<u32>,
    T: Sized + IntoBits<Output = Bits<T>>,
{
    type Item = Pos;

    fn next(&mut self) -> Option<Self::Item> {
        self.raw_iter.next()
    }
}

impl<T, Pos> IntoIterator for BitMap<T, Pos>
where
    Bits<T>: BitsOps<T>,
    Pos: Into<u32> + TryFrom<u32>,
    T: Sized + IntoBits<Output = Bits<T>>,
{
    type Item = Pos;

    type IntoIter = BitMapIter<T, Pos>;

    fn into_iter(self) -> Self::IntoIter {
        BitMapIter {
            raw_iter: self
                .raw
                .bits(..)
                .into_iter()
                .enumerate()
                .filter_map(|(pos, bit)| {
                    if bit.is_clr() {
                        return None;
                    }
                    if let Ok(output) = (pos as u32).try_into() {
                        Some(output)
                    } else {
                        None
                    }
                }),
        }
    }
}
